/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
* DataIntegrityTest.java
*
* Created on January 2, 2008, 1:54 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
 */
package main.genomemap;

import fs.genomemap.FileSettings;

import javautil.collections.ArrayUtil;
import javautil.collections.ListUtil;
import javautil.io.IOUtil;
import javautil.stat.FreqDist;
import javautil.swing.components.ProgressSupport;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author stewari1
 */
public class DataIntegrityTest extends ProgressSupport {

    /** Field description */
    private static final int STRATEGY_LATEST = 1;

    /** Field description */
    private static final int STRATEGY_OLDEST = 2;

    /** Field description */
    private boolean formatTestPassed = true;

    /** Field description */
    private final boolean dupTestPassed = true;

    /** Field description */
    private boolean correctionPassed = true;

    /** Field description */
    private int currentStrategy = 1;

    /**
     * Constructs ...
     */
    public DataIntegrityTest() {}

    public boolean runTests() {

        if (!runFileFmtIntegrityTest(5, 20)) {

            formatTestPassed = false;

            return false;
        }

        if (!runCloneProbeDupTest(25, 75)) return false;

        return true;
    }

    /**
     * Method description
     *
     * @param overAllProgStart description
     * @param overAllProgLen description
     *
     * @return description
     */
    private boolean runFileFmtIntegrityTest(int overAllProgStart, int overAllProgLen) {

        setProgress(overAllProgStart);
        setStatusInfo("Checking Presence of the necessary files");

        String errStr = FileSettings.checkInputCollection();

        if (errStr != null) {

            setStatusInfo("Some of the necessary files aren`t present");
            setLog(errStr);

            return false;

        } else {
            setStatusInfo("All the necessary files are present");
        }

        setProgress(overAllProgStart + overAllProgLen);

        return true;
    }

    /**
     * Method description
     *
     * @param overAllProgStart description
     * @param overAllProgLen description
     *
     * @return description
     */
    private boolean runCloneProbeDupTest(int overAllProgStart, int overAllProgLen) {

        for (int ch_id_index = 0; ch_id_index < 7; ch_id_index++) {

            setStatusInfo(
                "<html>Checking for possible duplicates in probe/clones <br> in Chromosome-"
                + (ch_id_index + 1) + "</html>");

            String clone_names_filePath = FileSettings.dataCollectionDir
                                          + FileSettings.FILE_CLONE_NAME_PTRN + (ch_id_index + 1)
                                          + ".txt";
            String probe_names_filePath = FileSettings.dataCollectionDir
                                          + FileSettings.FILE_PROBE_NAMES_PTRN + (ch_id_index + 1)
                                          + ".txt";
            String hybrid_filePath = FileSettings.dataCollectionDir + FileSettings.FILE_HYBRID_PTRN
                                     + (ch_id_index + 1) + ".txt";
            List cloneList       = null;
            List probeList       = null;
            int[][] hybridData   = null;
            String[] clone_names = null;
            String[] probe_names = null;

            try {

                clone_names = IOUtil.getTokens(
                    IOUtil.readFileContentToString(new File(clone_names_filePath)), null);
                probe_names = IOUtil.getTokens(
                    IOUtil.readFileContentToString(new File(probe_names_filePath)), null);
                hybridData = ArrayUtil.get2DIntMArray(new File(hybrid_filePath), false, ",");
                cloneList  = ListUtil.createArrayList(clone_names);
                probeList  = ListUtil.createArrayList(probe_names);

            } catch (FileNotFoundException ex) {

                ex.printStackTrace();
                setLog(ex.getMessage());

                return false;

            } catch (IOException ex) {

                ex.printStackTrace();
                setLog(ex.getMessage());

                return false;
            }


            // clones
            FreqDist cloneFreqDist                       = new FreqDist(cloneList);
            Map<Object, List<Integer>> dupClonePositions = cloneFreqDist.getDataPositions(1);
            Map<Object, Integer> cloneFreqDistMap        = cloneFreqDist.getFreqDistMap();
            Set<Integer> cloneIndices2beDeleted          = new HashSet<>();


            // show the duplicate clones, their frequency and occurences (here line numbers)
            if (!dupClonePositions.isEmpty()) {

                String str = "Duplicate Clones from file: " + clone_names_filePath + "\n";

                str += "Clone    freq     Line Numbers \n";

                Set keySet = dupClonePositions.keySet();

                for (Object obj : keySet) {

                    List<Integer> positions = dupClonePositions.get(obj);

                    str += obj + "   " + cloneFreqDistMap.get(obj) + "  " + positions + "\n";


                    // applying correction
                    if (currentStrategy == DataIntegrityTest.STRATEGY_LATEST)
                        positions.remove(Collections.max(positions));
                    if (currentStrategy == DataIntegrityTest.STRATEGY_OLDEST)
                        positions.remove(Collections.min(positions));

                    cloneIndices2beDeleted.addAll(positions);
                }

                setLog(str);
            }


            // probes
            FreqDist probeFreqDist                       = new FreqDist(probeList);
            Map<Object, List<Integer>> dupProbePositions = probeFreqDist.getDataPositions(1);
            Map<Object, Integer> probeFreqDistMap        = probeFreqDist.getFreqDistMap();
            Set<Integer> probeIndices2beDeleted          = new HashSet<>();


            // show the duplicate clones, their frequency and occurences (here line numbers)
            if (!dupProbePositions.isEmpty()) {

                String str = "Duplicate Probes from file: " + probe_names_filePath + "\n";

                str += "Probe    freq     Line Numbers \n";

                Set keySet = dupProbePositions.keySet();

                for (Object obj : keySet) {

                    List<Integer> positions = dupProbePositions.get(obj);

                    str += obj + "   " + probeFreqDistMap.get(obj) + "  " + positions + "\n";


                    // applying correction
                    if (currentStrategy == DataIntegrityTest.STRATEGY_LATEST)
                        positions.remove(Collections.max(positions));
                    if (currentStrategy == DataIntegrityTest.STRATEGY_OLDEST)
                        positions.remove(Collections.min(positions));

                    probeIndices2beDeleted.addAll(positions);
                }

                setLog(str);
            }


            // remove the clones and adjust hybridData
            if (!cloneIndices2beDeleted.isEmpty()) {

                int[] rowsTobeDeleted =
                    ArrayUtil.getIntegerArray(cloneIndices2beDeleted.toArray(new Integer[0]));

                hybridData  = ArrayUtil.deleteRows(hybridData, rowsTobeDeleted);
                clone_names = ArrayUtil.removeIndices(clone_names, rowsTobeDeleted);

                try {

                    IOUtil.writeToFile(new File(clone_names_filePath),
                                       IOUtil.toString(clone_names, "\n"));

                } catch (IOException ex) {

                    ex.printStackTrace();
                    setLog("The file " + clone_names_filePath + " couldn`t be written.");

                    correctionPassed = false;

                    return false;
                }
            }


            // remove probes and adjust hybridData
            if (!probeIndices2beDeleted.isEmpty()) {

                hybridData = ArrayUtil.transpose(hybridData);

                int[] colsTobeDeleted =
                    ArrayUtil.getIntegerArray(probeIndices2beDeleted.toArray(new Integer[0]));

                hybridData  = ArrayUtil.deleteRows(hybridData, colsTobeDeleted);
                probe_names = ArrayUtil.removeIndices(probe_names, colsTobeDeleted);
                hybridData  = ArrayUtil.transpose(hybridData);

                try {

                    IOUtil.writeToFile(new File(probe_names_filePath),
                                       IOUtil.toString(probe_names, "\n"));

                } catch (IOException ex) {

                    ex.printStackTrace();
                    setLog("The file " + probe_names_filePath + " couldn`t be written.");

                    correctionPassed = false;

                    return false;
                }
            }

            if (!cloneIndices2beDeleted.isEmpty() ||!probeIndices2beDeleted.isEmpty()) {

                try {

                    IOUtil.writeToFile(new File(hybrid_filePath),
                                       IOUtil.toString(ArrayUtil.getIntegerArray(hybridData), ",",
                                                       "\n"));

                } catch (IOException ex) {

                    ex.printStackTrace();
                    setLog("The file " + hybrid_filePath + " couldn`t be written.");

                    correctionPassed = false;

                    return false;
                }

            } else {

                setStatusInfo("<html>No duplicates were found for probe/clones <br> in Chromosome-"
                              + (ch_id_index + 1) + "</html>");
            }

            setProgress(overAllProgStart + (int) ((double) (ch_id_index + 1) / 7 * overAllProgLen));
        }

        return true;
    }

    public boolean isFormatTestPassed() {
        return formatTestPassed;
    }

    public boolean isDupTestPassed() {
        return dupTestPassed;
    }

    public boolean isCorrectionPassed() {
        return correctionPassed;
    }

    public void setCurrentStrategy(int currentStrategy) {
        this.currentStrategy = currentStrategy;
    }
}
